home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (C) 1994, Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
- * the contents of this file may not be disclosed to third parties, copied or
- * duplicated in any form, in whole or in part, without the prior written
- * permission of Silicon Graphics, Inc.
- *
- * RESTRICTED RIGHTS LEGEND:
- * Use, duplication or disclosure by the Government is subject to restrictions
- * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
- * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
- * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
- * rights reserved under the Copyright Laws of the United States.
- */
- /***************************************************************************
- *
- * @(#) - Oort - Multicast Socket Routines.
- *
- * $Id: multicast.c,v 1.2 1994/01/28 00:19:52 mtj Exp $
- *
- * Chris Fouts - Silicon Graphics, Inc.
- * October, 1991
- **************************************************************************/
- #include <stdlib.h>
- #include <bstring.h>
- #include <getopt.h>
- #include <string.h>
- #include <stdio.h>
- #include <time.h>
- #include <ctype.h>
- #include <unistd.h>
- #include <sys/types.h>
- #ifndef sgi
- #define sgi
- #define UN_SGI
- #endif /* sgi */
- #include <sys/socket.h>
- #include <net/if.h>
- #include <netinet/in.h>
- #include <net/soioctl.h>
- #include <arpa/inet.h>
- #ifdef UN_SGI
- #undef sgi
- #endif /* UN_SGI */
- #include <fcntl.h>
- #include "multicast.h"
-
-
- int ioctl( int fildes, int request, ... ) ;
-
- /* BEGIN PROTOTYPES -S multicast.c */
- static int checkInterface( const char *interface, int fd, char mode,
- struct in_addr *ifaddr ) ;
- /* END PROTOTYPES -S multicast.c */
-
-
- /*------------------------------------------------------------------------------
- * Open up a multicast socket for reading or writing.
- *----------------------------------------------------------------------------*/
- int
- openMulticastSocket(
- struct sockaddr_in *addr,
- u_short port,
- u_char ttl,
- u_char loop,
- const char *group,
- const char *interface,
- const char *mode_str
- )
- {
- int fd ;
- int st ;
- int on;
- char mode = tolower( *mode_str ) ;
- struct in_addr ifaddr;
- struct in_addr grpaddr;
- struct ip_mreq mreq;
-
- grpaddr.s_addr = inet_addr( group ) ;
- if( !IN_MULTICAST( grpaddr.s_addr ) )
- {
- fprintf( stderr, "Invalid multicast group address: %s\n",
- group ) ;
- return( -1 ) ;
- }
-
- if( strlen( mode_str ) != 1 || ( mode != 'r' && mode != 'w' ) )
- {
- fprintf( stderr, "openMulticastSocket: improper mode `%s'\n",
- mode_str ) ;
- return( -1 ) ;
- }
-
- fd = socket( AF_INET, SOCK_DGRAM, 0 ) ;
- if( fd < 0 )
- {
- perror( "socket" ) ;
- return( fd ) ;
- }
-
- bzero( addr, sizeof( *addr ) ) ;
- addr->sin_family = AF_INET ;
- addr->sin_addr.s_addr = INADDR_ANY ;
- addr->sin_port = htons( port ) ;
-
- ifaddr.s_addr = INADDR_ANY;
-
- if( interface != NULL &&
- ( st = checkInterface( interface, fd, mode, &ifaddr ) ) < 0 )
- {
- close( fd ) ;
- return( st ) ;
- }
-
- switch( mode )
- {
-
- case 'w' :
- if( setsockopt( fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl,
- sizeof(ttl) ) )
- {
- close( fd ) ;
- perror( "setsockopt TTL" ) ;
- return( -1 ) ;
- }
-
- if( setsockopt( fd, IPPROTO_IP, IP_MULTICAST_LOOP,
- &loop, sizeof(loop) ) )
- {
- close( fd ) ;
- perror( "setsockopt LOOP" ) ;
- return( -1 ) ;
- }
-
- addr->sin_addr = grpaddr;
- break ;
-
- case 'r' :
- /*
- * Allow multiple instances of this program to listen
- * on the same port on the same host. By default only
- * 1 program can bind to the port on a host.
- */
- on = 1;
- if( setsockopt( fd, SOL_SOCKET, SO_REUSEPORT, &on,
- sizeof(on) ) < 0 )
- {
- close( fd ) ;
- perror( "setsockopt REUSEPORT" ) ;
- return( -1 ) ;
- }
-
- if( bind( fd, addr, sizeof(*addr) ) < 0 )
- {
- close( fd ) ;
- perror( "bind" ) ;
- return( -1 ) ;
- }
-
- mreq.imr_multiaddr = grpaddr;
- mreq.imr_interface = ifaddr;
- if( setsockopt( fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
- &mreq, sizeof(mreq) ) < 0 )
- {
- close( fd ) ;
- perror( "setsockopt ADD" ) ;
- return( -1 ) ;
- }
- break ;
-
- }
-
- return( fd ) ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Make sure the specified interface exists and is capable of doing
- * multicasting.
- *----------------------------------------------------------------------------*/
- static int
- checkInterface(
- const char *interface,
- int fd,
- char mode,
- struct in_addr *ifaddr
- )
- {
- int i ;
- struct ifconf ifc ;
- struct ifreq *ifr ;
- char buf[BUFSIZ] ;
-
- ifc.ifc_len = sizeof( buf ) ;
- ifc.ifc_buf = buf ;
- if( ioctl( fd, SIOCGIFCONF, (char *) &ifc ) < 0 )
- {
- perror( "ioctl SIOCGIFCONF" ) ;
- return( -1 ) ;
- }
-
- ifr = ifc.ifc_req;
- for( i = ifc.ifc_len/sizeof(*ifr) ; --i >= 0 ; ifr++ )
- {
- if( ifr->ifr_addr.sa_family != AF_INET )
- continue ;
-
- if( strncmp( ifr->ifr_name, interface, strlen( ifr->ifr_name ) )
- == 0 )
- {
- /* Obtain the interface's assigned network address */
- *ifaddr = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr ;
-
- if( ioctl( fd, SIOCGIFFLAGS, (char *) ifr ) < 0 )
- {
- perror( "ioctl SIOCGIFFLAGS" ) ;
- return( -1 ) ;
- }
- if( !( ifr->ifr_flags & IFF_MULTICAST ) )
- {
- fprintf( stderr, "%s: interface doesn't support"
- " multicasting\n", interface ) ;
- return( -1 ) ;
- }
-
- /* Specify the interface to use when sending packets */
- if( mode == 'w' &&
- setsockopt( fd, IPPROTO_IP, IP_MULTICAST_IF,
- ifaddr, sizeof(*ifaddr) ) < 0 )
- {
- perror( "setsockopt MULTICAST" ) ;
- return( -1 ) ;
- }
- break;
- }
- }
-
- if( ifaddr->s_addr == INADDR_ANY )
- {
- fprintf( stderr, "%s: invalid or unknown interface\n",
- interface ) ;
- return( -1 ) ;
- }
-
- return( 0 ) ;
- }
-